/*
It is a application for event distribution to event n-consumers with m-sources.
Copyright (C) 2010 "Imran M Yousuf <imran@smartitengineering.com>"
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or any later
version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.smartitengineering.event.hub.core;
import com.smartitengineering.event.hub.api.Channel;
import com.smartitengineering.event.hub.api.Event;
import com.smartitengineering.event.hub.api.impl.APIFactory;
import com.smartitengineering.event.hub.common.Constants;
import com.smartitengineering.event.hub.spi.HubPersistentStorerSPI;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.atmosphere.annotation.Broadcast;
import org.atmosphere.annotation.Cluster;
import org.atmosphere.annotation.Suspend;
import org.atmosphere.cpr.Broadcaster;
import org.atmosphere.jersey.Broadcastable;
import org.atmosphere.plugin.jgroups.JGroupsFilter;
/**
*
* @author imyousuf
*/
@Path("/" + Constants.RSRC_PATH_CHANNEL_PREFIX + "/{" + Constants.RSRC_PATH_CHANNEL + "}/" + Constants.RSRC_PATH_CHANNEL_HUB)
public class ChannelHubResource extends AbstractChannelResource {
@PathParam(Constants.RSRC_PATH_CHANNEL)
private Broadcaster broadcaster;
@PathParam(Constants.RSRC_PATH_CHANNEL)
private String channelName;
@HeaderParam(Constants.AUTH_TOKEN_HEADER_NAME)
private String authToken;
@Context
private Request request;
@GET
@Suspend(outputComments = false)
@Produces
public Broadcastable register() {
checkChannelExistence();
checkAuthToken();
return new Broadcastable(broadcaster);
}
@Broadcast
@POST
@Cluster(name = "EventHub", value=JGroupsFilter.class)
public Response broadcast(@HeaderParam("Content-type") String contentType, String message) {
checkAuthToken();
checkChannelExistence();
final String eventContentType;
//HTTP Request entity body can not be blank
if (StringUtils.isBlank(message)) {
return Response.status(Status.BAD_REQUEST).build();
}
final boolean isHtmlPost;
if (StringUtils.isBlank(contentType)) {
eventContentType = MediaType.APPLICATION_OCTET_STREAM;
isHtmlPost = false;
}
else if (contentType.equals(MediaType.APPLICATION_FORM_URLENCODED)) {
eventContentType = MediaType.APPLICATION_OCTET_STREAM;
isHtmlPost = true;
try {
//Will search for the first '=' if not found will take the whole string
final int startIndex = message.indexOf("=") + 1;
//Consider the first '=' as the start of a value point and take rest as value
final String realMsg = message.substring(startIndex);
//Decode the message to ignore the form encodings and make them human readable
message = URLDecoder.decode(realMsg, "UTF-8");
}
catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
}
else {
eventContentType = contentType;
isHtmlPost = false;
}
Event event = APIFactory.getEventBuilder().eventContent(APIFactory.getContent(eventContentType, IOUtils.
toInputStream(message))).build();
final Channel channel = HubPersistentStorerSPI.getInstance().getStorer().getChannel(channelName);
event = HubPersistentStorerSPI.getInstance().getStorer().create(channel, event);
//Add a new line at the end of the message to ensure that the message is flushed to its listeners
message = message + "\n";
Broadcastable broadcastable = new Broadcastable(message, broadcaster);
ResponseBuilder builder = Response.ok(broadcastable);
builder.location(getAbsoluteURIBuilder().path(EventResource.class).build(event.getPlaceholderId()));
if (isHtmlPost) {
builder.status(Response.Status.SEE_OTHER);
builder.location(getAbsoluteURIBuilder().path(ChannelEventsResource.class).build(channelName));
}
return builder.build();
}
@Override
protected String getChannelName() {
return channelName;
}
@Override
protected String getAuthToken() {
return authToken;
}
}